﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Okra.Data;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using XBMCRPC;
using XBMCRPC.List;
using XBMCRPC.Video.Fields;
using XbmcRt2.Data;

namespace XbmcRt2
{
    class ImageManager
    {
        class ImageRequest
        {
            public string ImgUri { get; set; }
            public Action<IRandomAccessStream> Callback { get; set; }

            public ImageRequest(string imgUri, Action<IRandomAccessStream> callback)
            {
                ImgUri = imgUri;
                Callback = callback;
            }
        }

        private readonly Client _xbmc;

        public ImageManager(Client xbmc)
        {
            _xbmc = xbmc;
            _cancellationSource= new CancellationTokenSource();
            Task.Factory.StartNew(()=> Loader(_cancellationSource.Token), _cancellationSource.Token);

        }

        private void Loader(CancellationToken token)
        {
            while (!token.IsCancellationRequested)
            {
                _requestsAvailable.WaitOne();
                _requestsAvailable.Reset(); 
                while(_requests.Count!=0)
                {
                    var request = _requests.Dequeue();
                    var task=GetImageNow(request);
                    try
                    {
                        task.Wait();
                    }
                    catch (Exception)
                    {
                    }
                    

                }
            }
        }

        Queue<ImageRequest> _requests=new Queue<ImageRequest>();

        ManualResetEvent _requestsAvailable=new ManualResetEvent(false);
        private CancellationTokenSource _cancellationSource;

        public void GetImage(string imgUri, Action<IRandomAccessStream> callback)
        {
            _requests.Enqueue(new ImageRequest(imgUri,callback));
            _requestsAvailable.Set();

        }

        async private Task GetImageNow(ImageRequest request)
        {
            var tmpDir = ApplicationData.Current.TemporaryFolder;
            StorageFile file=null;
            var fileName = Uri.EscapeDataString(request.ImgUri);
            try
            {
                file = await tmpDir.GetFileAsync(fileName);
            }
            catch (Exception)
            {
                
            }
            if(file==null)
            {
                var stream = await _xbmc.GetImageStream(request.ImgUri);
                file = await tmpDir.CreateFileAsync(fileName);
                var fileStream = await file.OpenStreamForWriteAsync();
                await stream.CopyToAsync(fileStream);
                fileStream.Dispose();
            }
            var imgStream= await file.OpenAsync(FileAccessMode.Read);


            request.Callback(imgStream);
        }

 
    }

    class MovieSource:PagedDataListSource<MovieVM>
    {
        public static MovieSource Current=new MovieSource();
        public static MovieVM Selected;

        private static VirtualizingDataList<MovieVM> _virtualizingDataList;
        public static VirtualizingDataList<MovieVM> VirtualizingDataList
        {get
        {
            if(_virtualizingDataList==null)
            {
                _virtualizingDataList=new VirtualizingDataList<MovieVM>(Current);
            }
            return _virtualizingDataList;
        }}

        private Client _xbmc;
        private ImageManager _imgMan;

        #region Overrides of PagedDataListSource<MovieVM>

        public MovieSource()
        {
            _xbmc = new XBMCRPC.Client("homeserver",85,"xbmc","xbmc");
            _imgMan = new ImageManager(_xbmc);
        }

        async protected override Task<DataListPageResult<MovieVM>> FetchCountAsync()
        {
            return await FetchPageAsync(1);
        }

        async protected override Task<DataListPageResult<MovieVM>> FetchPageSizeAsync()
        {
            return await FetchPageAsync(1);

        }

        async protected override Task<DataListPageResult<MovieVM>> FetchPageAsync(int pageNumber)
        {
            var mvs = await _xbmc.VideoLibrary.GetMovies(Movie.AllFields(), new Limits() { start = (pageNumber-1)*20, end =(pageNumber-1)*20 +  20 }, new Sort(){method= Sort.methodEnum.title, ignorearticle = true, order = Sort.orderEnum.@ascending});
            var list = mvs.movies.Select(m => new MovieVM(m,_imgMan)).ToList();
            return new DataListPageResult<MovieVM>(mvs.limits.total, 20, pageNumber, list);
        }

        #endregion
    }

    internal class MovieVM:XbmcRt2.Common.BindableBase
    {
        private readonly ImageManager _imgMan;


        public MovieVM(XBMCRPC.Video.Details.Movie movie,ImageManager imgMan)
        {
            _imgMan = imgMan;
            Title = movie.title;
            Subtitle = movie.tagline;
            Year = movie.year;
            Runtime = movie.runtime;
            Content = movie.plot;
            WatchedCheck = movie.playcount>0 ? Visibility.Visible : Visibility.Collapsed;
            _fanart = movie.fanart;
            imgMan.GetImage(movie.thumbnail,SetImage);
            
        }

        public int Runtime { get; set; }
        public int Year { get; set; }
        public Visibility WatchedCheck { get; set; }
        public string Title { get; set; }
        public string Subtitle { get; set; }
        public string Content { get; set; }

        private ImageSource _image = null;
        public ImageSource Image
        {
            get
            {

                return this._image;
            }
        }

        private ImageSource _fanArtImage = null;
        private string _fanart;

        public ImageSource FanArtImage
        {
            get
            {
                if(_fanArtImage==null)
                {
                    _imgMan.GetImage(_fanart,SetFanArt);
                }
                return this._fanArtImage;
            }
        }

        private void SetFanArt(IRandomAccessStream obj)
        {
            Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
                CoreDispatcherPriority.Normal, () =>
                {
                    var bi = new BitmapImage();
                    bi.SetSource(obj);
                    _fanArtImage = bi;
                    this.OnPropertyChanged("FanArtImage");

                });
        }


        private void SetImage(IRandomAccessStream randomAccessStream)
        {
            Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
                CoreDispatcherPriority.Normal, () =>
                                                   {
                                                       var bi = new BitmapImage();
                                                       bi.SetSource(randomAccessStream);
                                                       _image = bi;
                                                       this.OnPropertyChanged("Image");

                                                   });
        }


    }


}
